package service

import (
	"errors"
	"fmt"
	"github.com/go-admin-team/go-admin-core/sdk/service"
	"go-admin/app/admin/cicd/cd"
	"go-admin/app/admin/cicd/ci"
	"gorm.io/gorm"
	"strings"

	"go-admin/app/admin/models"
	"go-admin/app/admin/service/dto"
	"go-admin/common/actions"
	cDto "go-admin/common/dto"
)

type App struct {
	service.Service
}

// GetPage 获取App列表
func (e *App) GetPage(c *dto.AppGetPageReq, p *actions.DataPermission, list *[]models.App, count *int64) error {
	var err error
	var data models.App

	err = e.Orm.Model(&data).
		Scopes(
			cDto.MakeCondition(c.GetNeedSearch()),
			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
			actions.Permission(data.TableName(), p),
		).
		Preload("Environments").Find(list).Limit(-1).Offset(-1).
		Count(count).Error
	if err != nil {
		e.Log.Errorf("AppService GetPage error:%s \r\n", err)
		return err
	}
	return nil
}

// Get 获取App对象
func (e *App) Get(d *dto.AppGetReq, p *actions.DataPermission, model *models.App) error {
	var data models.App

	err := e.Orm.Model(&data).
		Scopes(
			actions.Permission(data.TableName(), p),
		).
		Preload("Environments").First(model, d.GetId()).Error
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		err = errors.New("查看对象不存在或无权查看")
		e.Log.Errorf("Service GetApp error:%s \r\n", err)
		return err
	}
	if err != nil {
		e.Log.Errorf("db error:%s", err)
		return err
	}
	return nil
}

// Insert 创建App对象
func (e *App) Insert(c *dto.AppInsertReq) error {
	var err error
	var data models.App
	if !strings.HasPrefix(c.CodeRepo, "git@") {
		return errors.New("代码仓库地址要使用ssh的方式")
	}
	if c.ApolloConfigURL != "" && !strings.HasPrefix(c.ApolloConfigURL, "http") {
		return errors.New("阿波罗地址要以http开头")
	}
	c.Generate(&data)
	tx := e.Orm.Begin()
	err = tx.Create(&data).Error
	if err != nil {
		e.Log.Errorf("AppService Insert error:%s \r\n", err)
		return err
	}

	var environments []models.Environment
	if err := e.Orm.Where("id in ?", c.EnvironmentIds).Preload("Cluster").Find(&environments).Error; err != nil {
		tx.Rollback()
		return err
	}

	if len(environments) > 0 {
		for _, env := range environments {
			pipeline := &ci.PipelineOptions{
				BuildEnv:          env.Code,
				Namespace:         env.Namespace,
				Credential:        env.Credential,
				CodeBranch:        env.CodeBranch,
				ImageUrl:          env.ImageUrl,
				ImageProject:      env.ImageProject,
				Notify:            env.Notify,
				Port:              data.Port,
				AppName:           data.Name,
				CodeRepo:          data.CodeRepo,
				ApolloConfigURL:   c.ApolloConfigURL,
				ApolloServiceName: c.ApolloServiceName,
				CpuRequest:        c.CpuRequest,
				CpuLimit:          c.CpuLimit,
				MemRequest:        c.MemRequest,
				MemLimit:          c.MemLimit,
				DockerfileName:    c.DockerfileName,
			}
			var jenkins models.Jenkins
			if err := e.Orm.Where("id=?", env.JenkinsId).First(&jenkins).Error; err != nil {
				tx.Rollback()
				return err
			}

			client, err := ci.CreateServer(jenkins.Address, jenkins.Username, jenkins.Password)
			if err != nil {
				tx.Rollback()
				return err
			}

			jobXml, err := pipeline.ParseJobXml()
			if err != nil {
				tx.Rollback()
				return err
			}

			if err := client.CreateJob(jobXml, fmt.Sprintf("%s-%s", pipeline.BuildEnv, pipeline.AppName)); err != nil {
				tx.Rollback()
				return err
			}

			if env.Cluster.Credential == "" {
				tx.Rollback()
				return errors.New("kubeconfig 不能为空")
			}

			clientset, err := cd.New([]byte(env.Cluster.Credential))
			if err != nil {
				tx.Rollback()
				return err
			}
			if err := clientset.CreateDeployment(pipeline); err != nil {
				tx.Rollback()
				return err
			}
			if err := clientset.CreateService(pipeline); err != nil {
				tx.Rollback()
				return err
			}
		}
	}
	tx.Commit()
	return nil
}

// Update 修改App对象
func (e *App) Update(c *dto.AppUpdateReq, p *actions.DataPermission) error {
	var err error
	var data = models.App{}
	e.Orm.Scopes(
		actions.Permission(data.TableName(), p),
	).First(&data, c.GetId())
	c.Generate(&data)

	db := e.Orm.Save(&data)
	if err = db.Error; err != nil {
		e.Log.Errorf("AppService Save error:%s \r\n", err)
		return err
	}
	if db.RowsAffected == 0 {
		return errors.New("无权更新该数据")
	}
	return nil
}

// Remove 删除App
func (e *App) Remove(d *dto.AppDeleteReq, p *actions.DataPermission) error {
	var data models.App

	tx := e.Orm.Begin()

	db := tx.Model(&data).
		Scopes(
			actions.Permission(data.TableName(), p),
		).Delete(&data, d.GetId())
	if err := db.Error; err != nil {
		tx.Rollback()
		e.Log.Errorf("Service RemoveApp error:%s \r\n", err)
		return err
	}
	if db.RowsAffected == 0 {
		tx.Rollback()
		return errors.New("无权删除该数据")
	}
	var appEnvironment models.AppEnvironment
	if err := tx.Model(&appEnvironment).Where("app_id=?", d.GetId()).Delete(&appEnvironment).Error; err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}
